#pragma once
#include<string>
#include<vector>
#include<regex>
#include"../HttpRequest/HttpRequest.hpp"
#include"../Util/Util.hpp"
#include"../../Server/TcpServer/TcpServer.hpp"
#include"../HttpContext/HttpContext.hpp"
#include"../HttpResponse/HttpResponse.hpp"
#define DEFAULT_TIMEOUT 10
//Http服务器模块
//元素：GET/POST/DELETE/HEAD请求方法的路由表，静态资源根目录，tcp服务器
//功能: 
class HttpServer{
private:
    using Handler = std::function<void(const HttpRequest& req, HttpResponse& rsp)>;
    using Route = std::vector<std::pair<std::regex, Handler>>;
    Route _get_route;
    Route _post_route;
    Route _delete_route;
    Route _put_route;
    std::string _static_dir;
    TcpServer _server;

private:
    //错误的请求响应
    void ErrnoHandler(const HttpRequest &req, HttpResponse& rsp)
    {
        //组织一个显示错误的页面
        std::string str;
        str += "<html>";
        str += "<head>";
        str += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        str += "</head>";
        str += "<body>";
        str += "<h1>";
        str += std::to_string(rsp._status);
        str += " ";
        str += Util::StatusMessage(rsp._status);
        str += "</h1>";
        str += "</body>";
        str += "</html>";
        //将内容放到rdp的body中
        rsp.SetContent(str, "text/html");
    }
    //将HttpResponse中的要素按照http协议格式进行组织，发送
    void WriteResponse(const ConnectPtr conn, const HttpRequest& req, HttpResponse& rsp)
    {
        //1.完善头部字段
        //长短连接
        if(req.Close() == true)
        {
            rsp.SetHeader("Connection", "close");
        }
        else
        {
            rsp.SetHeader("Connection", "keep-alive");
        }
        //正文长度
        if(rsp._body.empty() == false && rsp.HasHeader("Content-Length") == false)
        {
            rsp.SetHeader("Content-Length", std::to_string(rsp._body.size()));
        }
        //文本类型
        if (rsp._body.empty() == false && rsp.HasHeader("Content-Type") == false)
        {
            rsp.SetHeader("Content-Type", "application/octet-stream");
        }
        //重定向
        if(rsp._redirect_flag == true)
        {
            rsp.SetHeader("Location", rsp._redirect_url);
        }
        //2.将rsp中的数据按照http进行组织
        std::stringstream str;
        //响应行
        str << req._vision << ' ' << std::to_string(rsp._status) << ' ' << Util::StatusMessage(rsp._status) << "\r\n";
        //响应头部
        for(auto& e:rsp._headers)
        {
            str << e.first << ": " << e.second << "\r\n";
        }
        str << "\r\n";
        //响应内容
        str << rsp._body;
        //3.发送数据
        std::string test = str.str();
        std:: cout << test;
        conn->SendInLoop(str.str().c_str(), str.str().size());
    }

    //判断是不是静态资源的请求
    bool IsFileHandler(const HttpRequest& req, HttpResponse& rsp)
    {
        //要有静态资源路径
        if(_static_dir.empty() == true)
        {
            return false;
        }
        //请求方法必须是GET/HEAD
        if(req._method != "GET" && req._method != "HEAD")
        {
            return false;
        }
        //请求资源路径有效
        if(Util::ValidPath(req._path) == false)
        {
            return false;
        }
        //请求的资源必须存在且是一个普通文件
        //1.先拼接资源路径
        std::string path = _static_dir + req._path;
        //2.如果req._path的最后一个是/，就要在后面添加默认路径index.html
        if(req._path.back() == '/')
        {
            path += "index.html";
        }
        //3.资源是一个普通文件
        if(Util::IsRegular(path) == false)
        {
            return false;
        }
        return true;
    }
    //对静态资源请求的处理,将请求的文件内容放到rsp的body中，并设置mime
    void FileHandler(const HttpRequest& req, HttpResponse& rsp)
    {
        //获取资源路径
        std::string path = _static_dir + req._path;
        if(req._path.back() == '/')
        {
            path += "index.html";
        }
        bool ret = Util::ReadFile(path, rsp._body);
        if(ret == false)
        {
            return;
        }
        std::string mime = Util::FileMime(path);
        rsp.SetHeader("Content-Type", mime);
        return;
    }
    //对功能型请求进行处理
    void FunctionHandler(HttpRequest& req, HttpResponse& rsp, Route& route)
    {
        for(auto& it:route)
        {
            const std::regex& rgx = it.first;
            const Handler& handler = it.second;
            bool ret = std::regex_match(req._path, req._match, rgx);
            if(ret == false)
            {
                continue;
            }
            return handler(req, rsp);//处理请求
        }
        //未找到方法，错误码设置为404
        rsp._status = 404;
    }
    //对请求进行处理，根据请求的类型
    void Router(HttpRequest& req, HttpResponse& rsp)
    {
        //对请求进行分类
        
        //如果是静态资源请求，就处理
        if(IsFileHandler(req, rsp) == true)
        {   
            ERR_LOG("静态资源请求");
            return FileHandler(req, rsp);
        }
        //如果是功能请求，就先查看该功能的回调函数是否存在，然后处理
        if(req._method == "GET" || req._method == "HEAD")
        {
            ERR_LOG("GET请求");
            return FunctionHandler(req, rsp, _get_route);
        }
        if(req._method == "PUT")
        {
            ERR_LOG("PUT请求");
            return FunctionHandler(req, rsp, _put_route);
        }
        if(req._method == "POST")
        {
            return FunctionHandler(req, rsp, _post_route);
        }
        if(req._method == "DELETE")
        {
            return FunctionHandler(req, rsp, _delete_route);
        }

        //如果二者都不是，就返回405 Method Not Allowed
        rsp._status = 405;
        return;
    }
    //为连接设置上下文
    void OnConnect(const ConnectPtr& conn)
    {
        conn->SetContext(HttpContext());
        return;
    }
    //缓冲区请求的获取解析，发送响应
    void OnMessage(const ConnectPtr& conn, Buffer* buffer)
    {
        while(buffer->get_readable_size() > 0)
        {
            //1.获取连接的上下文
            HttpContext* context = std::any_cast<HttpContext>(conn->GetContext());
            //2.通过上下文对缓冲区进行解析，得到HttpRequest
            context->RecvHttpRequest(*buffer);
            HttpRequest& req = context->GetRequest();
            HttpResponse rsp(context->GetResponseStatus());
            //处理出错
            if(context->GetResponseStatus() >= 400)
            {
                //进行错误响应
                ErrnoHandler(req, rsp);//填充一个错误页面到rsp
                WriteResponse(conn, req, rsp);//将错误页面发送
                //重置上下文
                context->Reset();
                //把缓冲区清空
                buffer->move_read_pos(buffer->get_readable_size());
                //关闭连接
                conn->CloseInLoop();
                return;
            }
            //请求的数据没有接收完整,则退出，等新数据到来再重新继续处理
            if(context->GetRequestStatus() != request_over)
            {
                return;
            }
            //3.对Request进行处理
            Router(req, rsp);
            //4.组织HttpResponse并发送
            WriteResponse(conn, req, rsp);
            //5.重置上下文
            context->Reset();
            //6.根据长短连接判断是否关闭连接或者继续处理
            if(rsp.Close() == true)     {
                conn->CloseInLoop();
            }
        }
    }
public:
    HttpServer(uint16_t port, int timeout = DEFAULT_TIMEOUT)
    :_server(port)
    {
        _server.SetInactiveRelease(timeout);
        _server.SetConnectedCallback(std::bind(&HttpServer::OnConnect, this, std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
    }

    //设置静态资源路径
    void SetBaseDir(const std::string path)
    {
        bool ret = Util::IsDirectory(path);
        if(ret == false)
            return;
        _static_dir = path;
    }

    /*设置/添加，请求（请求的正则表达）与处理函数的映射关系*/
    void Get(const std::string& pattern, const Handler& handler)
    {
        _get_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void Post(const std::string& pattern, const Handler& handler)
    {
        _post_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void Put(const std::string& pattern, const Handler& handler)
    {
        _put_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void Delete(const std::string& pattern, const Handler& handler)
    {
        _delete_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void SetThreadCount(int count) 
    {
        _server.SetThreadCount(count);
    }
    void Listen() 
    {
        _server.Start();
    }
};